/*
 * funcionesPFS.c
 *
 *  Created on: 25/09/2011
 *      Author: utn_so
 */

#include "libPFS.h"

void handshake (int32_t socket)
{
        t_NIPC paqueteRecibido, respuesta;
        int32_t valorRetorno;

        NIPC_crearpaquete(NULL, HANDSHAKE, 0, NULL, 0,&respuesta);
        valorRetorno = NIPC_enviar(socket,respuesta);

        valorRetorno = NIPC_recibir (socket, &paqueteRecibido);
        if (paqueteRecibido.PayloadDescriptor == HANDSHAKE)
        {
            if(paqueteRecibido.PayloadLength != 0)
              {
              printf("Error:%s",paqueteRecibido.payload);
              exit(0);
              }
        }
        else
          {
          printf("No Recibi el Handshake al inicio, Finalizo Proceso\n");
          exit(0);
          }

}
void loguearListaClusters(const char *path,uint32_t clusterInicial)
{
  char *listaClusters,*aux;
  extern stFatConMutex stFatMutex;
  extern t_log *loguear;

  uint32_t recorroFAT=0;
  if (clusterInicial == 0)
    log_info (loguear, "PFS","\nEl Archivo:%s\nEsta Vacio, No tiene CLusters Asociados\n",path);
  else
  {
      aux = (char *)calloc(1,sizeof(char) + sizeof(uint32_t));
      listaClusters = (char *)calloc(51,sizeof(uint32_t) + sizeof(char));
      while (recorroFAT < 50 && clusterInicial != FINARCHIVO)
      {
          sprintf(aux,"%d ",clusterInicial);
          strcat(listaClusters,aux);
          clusterInicial = stFatMutex.fatRegion[clusterInicial];
          recorroFAT++;
      }
      log_info (loguear, "PFS","\nCusters De:%s\nLista:%s\n",path,listaClusters);
      liberarMemoria(&aux);
      liberarMemoria(&listaClusters);
  }

}
void atiendeFatRegion ()
{
  extern t_config archivoCfg;
  extern stFatConMutex stFatMutex;
  extern stBootSector sectorBoot;
  extern stBits *BitVecFat;
  uint32_t cantBytes = 4,recorroBit=0,bool = 0,offset=0,cantParcial=0;
  uint32_t cantSecPorBloque,primerSecBloque,nroBloqueAEscribir=0;
  uint32_t cantClusters = TAMSECTOR / cantBytes * sectorBoot.BPB_FATSz32;

  cantSecPorBloque = ( archivoCfg.tamanioBloque * TAMSECTOR ) / cantBytes;

  while(1)
    {

      sleep(archivoCfg.tiempoEsperaFat);

      recorroBit = 0;
      nroBloqueAEscribir = 0;
      while (recorroBit < cantClusters)
      {

        bool=0;
        cantParcial=0;

        while (recorroBit < cantClusters  && bool == 0)
        {
          if (BitVecFat[recorroBit].clean != 0)
                  bool = 1;
          if (cantParcial == cantSecPorBloque)
            {
              cantParcial=0;
              nroBloqueAEscribir++;
            }
          recorroBit++;
          cantParcial++;
        }

        if (bool == 1) // Alguno de Ese Bloque Fue Modificado, Mando A Escribir El Bloque
          {
            primerSecBloque = obtenerPrimerSectorDeUnBloque(nroBloqueAEscribir);
            primerSecBloque += sectorBoot.BPB_RsvdSecCnt;
            offset = cantSecPorBloque * nroBloqueAEscribir;

            enviarPeticionesEscritura(primerSecBloque,(char *)(stFatMutex.fatRegion + offset)); //Armar Cluster
            limpiarBitVector(cantSecPorBloque,nroBloqueAEscribir,offset);

          }
        nroBloqueAEscribir++;
        recorroBit = cantSecPorBloque * nroBloqueAEscribir;
      }

    }

}
void limpiarBitVector(uint32_t cantidadBloque,uint32_t nroBloque,uint32_t offset)
{
  uint32_t recorroBit=0;
  extern stBits *BitVecFat;
  pthread_mutex_lock (&BitVecFat->bloqueastBits);
  while (recorroBit < cantidadBloque)
    {
     BitVecFat[recorroBit + offset].clean = 0;
     recorroBit++;
    }
  pthread_mutex_unlock (&BitVecFat->bloqueastBits);
}

t_config abrirArchivoConfig ()
{
  t_config config;
  char *pPuerto, *pCantConex, *pTamBloque,*pFat, *pTamCache = NULL;
  char tokenPuerto [] = "Puerto Destino";
  char tokenDirIp [] = "Direccion Ip";
  char CantConexiones [] = "Cantidad Conexiones";
  char tokenBloque [] = "Tamanio Bloque";
  char tokenCache [] = "Tam Cache";
  char tokenFat [] = "Actualiza Fat Cada";

  config.pDirIp = setearCfgPFS (tokenDirIp);
  pPuerto = setearCfgPFS (tokenPuerto);
  pCantConex = setearCfgPFS (CantConexiones);
  pTamBloque = setearCfgPFS (tokenBloque);
  pTamCache = setearCfgPFS (tokenCache);
  pFat = setearCfgPFS (tokenFat);

  config.tamanioBloque = stringAInt16 (pTamBloque);
  config.puerto = stringAInt16 (pPuerto);
  config.cantidadConexiones = stringAInt16 (pCantConex);
  config.tamCache = stringAInt16 (pTamCache) * 1024;
  config.tiempoEsperaFat = stringAInt16 (pFat) * 60;

  return config;
}

char *setearCfgPFS (char *token)
{

  int32_t leerCfg = 0;
  char *pRetorno;
  char *path;
  path = getcwd (NULL, TAMSECTOR);
  strcat (path, pathCfg);
  leerCfg = leerConfiguracion (path, token, &pRetorno);
  free (path);
  if (leerCfg == Retorno_Error)
    {
      exit (EXIT_FAILURE);
    }

  return pRetorno;
}

int16_t stringAInt16 (char *pPuerto)
{
  int32_t memoriaLiberada = 0;
  int16_t puerto = atoi (pPuerto);
  memoriaLiberada = liberarMemoria (&pPuerto);
  return puerto;
}

void leerFatRegion ()
{
  extern t_config archivoCfg;
  extern stBootSector sectorBoot;
  extern stBits *BitVecFat;
  extern stFatConMutex stFatMutex;
  int16_t tamCluster = sectorBoot.BPB_SecPerClus * TAMSECTOR;
  uint32_t bloqueLeido = 0, acumulador = 0, nroCluster, iCluster = 0,
      primerSecBloque, cantBytes = 4;
  int32_t cantClusters = TAMSECTOR / cantBytes * sectorBoot.BPB_FATSz32;
  uint32_t cantClusPerBloque = cantidadClustersDelBloque ();
  char *vecSectores;
  stFatMutex.fatRegion = ( uint32_t *) calloc (cantClusters, sizeof(uint32_t)); /* --> Ocupa 0.5 MB en memoria */
  BitVecFat = ( stBits *) calloc (cantClusters, sizeof(stBits));

  while (bloqueLeido < (sectorBoot.BPB_FATSz32 / archivoCfg.tamanioBloque))
    {

      primerSecBloque = obtenerPrimerSectorDeUnBloque (
          (sectorBoot.BPB_RsvdSecCnt / archivoCfg.tamanioBloque) + bloqueLeido);
      armarCluster (primerSecBloque, NULL,&vecSectores);

      while (acumulador < tamCluster)
        {
          memcpy (&nroCluster, vecSectores + acumulador, cantBytes);
          stFatMutex.fatRegion [iCluster] = nroCluster;

          if (stFatMutex.fatRegion [iCluster] != 0x00)
            {
              BitVecFat [iCluster].ocupado = 1;

            }
          acumulador += cantBytes;
          iCluster++;
        }
      bloqueLeido += cantClusPerBloque;
      acumulador = 0;
      free (vecSectores);
    }

}

int32_t recorroBitVector (int32_t cantClusters)
{
  int32_t resultado = 0, iterar = 0;
  extern stBits *BitVecFat;

  while (iterar < cantClusters)
    {
      if (BitVecFat [iterar].ocupado == 0)
        resultado++;
      iterar++;
    }
  return resultado;
}

uint32_t obtenerBitLibre ()
{
  extern stBootSector sectorBoot;
  extern stBits *BitVecFat;
  uint32_t cantBytes = 4,iterar =0;
  uint32_t cantClusters = TAMSECTOR / cantBytes * sectorBoot.BPB_FATSz32;

  while (iterar < cantClusters )
    {
      if (BitVecFat [iterar].ocupado != 0)
        iterar++;
      else
        {
         pthread_mutex_lock(&BitVecFat->bloqueastBits);
         BitVecFat [iterar].ocupado = 1;
         pthread_mutex_unlock(&BitVecFat->bloqueastBits);
         return iterar;
        }

    }
  pthread_mutex_unlock(&BitVecFat->bloqueastBits);
  return -1; //Se LLeno el Disco
}
void crearEntradasComunes(uint32_t clusterDirectorio,uint32_t nuevoClusterDir)
{
  extern stBootSector sectorBoot;
  stDirectoryTable stDirAEscribir;
  uint16_t clusH=0,clusL=0,offset=0;
  char *bloque,*retorno;
  uint32_t deClusABloque,primerSecBloque;
  bloque = (char *)calloc(sectorBoot.BPB_SecPerClus,TAMSECTOR);

  memset(&stDirAEscribir,'\0',sizeof(stDirAEscribir));
  stDirAEscribir.DT_FileName[0] = RETORNADIRECTORIO;
  traducirLittleEndian(nuevoClusterDir,&clusL,&clusH);
  stDirAEscribir.DT_ClusterInicialHigh = clusH;
  stDirAEscribir.DT_ClusterInicialLow = clusL;
  stDirAEscribir.DT_FileAtrib = ENTRADADIR;
  memcpy(bloque,&stDirAEscribir,sizeof(stDirAEscribir));
  offset += sizeof(stDirAEscribir);

  memset(&stDirAEscribir,'\0',sizeof(stDirAEscribir));
  clusH=0;
  clusL=0;
  stDirAEscribir.DT_FileName[0] = RETORNADIRECTORIO;
  stDirAEscribir.DT_FileName[1] = RETORNADIRECTORIO;
  if (clusterDirectorio != sectorBoot.BPB_RootClus)
    traducirLittleEndian(clusterDirectorio,&clusL,&clusH);
  stDirAEscribir.DT_ClusterInicialHigh = clusH;
  stDirAEscribir.DT_ClusterInicialLow = clusL;
  stDirAEscribir.DT_FileAtrib = ENTRADADIR;

  memcpy(bloque + offset ,&stDirAEscribir,sizeof(stDirAEscribir));
  deClusABloque = deClusterABloque (nuevoClusterDir);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque, bloque,&retorno);

  free(bloque);
  free(retorno);
}
uint32_t obtenerclusterNuevo()
{
  extern stBits *BitVecFat;
  extern stFatConMutex stFatMutex;
  uint32_t retorno;
  retorno = obtenerBitLibre();
  pthread_mutex_lock(&stFatMutex.bloqueaFat);
  stFatMutex.fatRegion[retorno] = FINARCHIVO;
  pthread_mutex_unlock(&stFatMutex.bloqueaFat);
  pthread_mutex_lock(&BitVecFat->bloqueastBits);
  BitVecFat[retorno].clean = 1;
  pthread_mutex_unlock(&BitVecFat->bloqueastBits);

  return retorno;
}
void separaCadenas (const char *directorio, char **directorioABuscar,char **directorioACrear)
{
  *directorioABuscar = ( char *) calloc (strlen(directorio), sizeof(char));
  *directorioACrear = ( char *) calloc (13, sizeof(char));
  *directorioACrear = strrchr (directorio, '/');
  *directorioACrear = *directorioACrear + 1;
  memcpy (*directorioABuscar, directorio, strlen (directorio) - strlen(*directorioACrear));
}

int32_t compararCadenas (const char *to, const char *from, char **nombreTo,
    char **nombreFrom) //El Valor de Retorno me dice si es un move
{
  int32_t retorno;
  char *directorio1 = NULL, *directorio2 = NULL;
  separaCadenas (to, &directorio1, nombreTo);
  separaCadenas (from, &directorio2, nombreFrom);
  retorno = strcmp (directorio1, directorio2);
  free (directorio1);
  free (directorio2);
  return retorno;
}

uint32_t obtenerClusterSiguiente (uint32_t clusterActual)
{
  extern stFatConMutex stFatMutex;
  uint32_t clusterARetornar;
  clusterARetornar = stFatMutex.fatRegion [clusterActual];
  if (clusterARetornar != FINARCHIVO)
    return clusterARetornar;
  return FINARCHIVO;
}

/* Obtengo la Cantidad De Clusters que Ocupaba y se lo resto a la nueva cantidad, la dif es lo que tengo que pedir */
uint32_t obtenerUltimoCluster(uint32_t clusterInicial)
{
  uint32_t recorroFat=clusterInicial;
  uint32_t clusterAnterior=0;
  while (recorroFat != FINARCHIVO)
    {
      clusterAnterior = recorroFat;
      recorroFat = obtenerClusterSiguiente(recorroFat);
    }
  return clusterAnterior;
}
uint32_t obtenerAnteUltimo(uint32_t clusterInicial,uint32_t ultimoCluster)
{
  extern stFatConMutex stFatMutex;
  uint32_t clusterAnterior=clusterInicial;
  while (stFatMutex.fatRegion[clusterAnterior] != ultimoCluster)
    {
      clusterAnterior = stFatMutex.fatRegion[clusterAnterior];
    }
  return clusterAnterior;
}
void asignarNuevoCluster(uint32_t ultimoClusArchivo,uint32_t nuevoCluster)
{
  extern stFatConMutex stFatMutex;
  extern stBits *BitVecFat;

  pthread_mutex_lock(&stFatMutex.bloqueaFat);
  pthread_mutex_lock(&BitVecFat->bloqueastBits);
  stFatMutex.fatRegion[ultimoClusArchivo] = nuevoCluster;
  stFatMutex.fatRegion[nuevoCluster] = FINARCHIVO;
  BitVecFat[ultimoClusArchivo].clean = 1;
  BitVecFat[nuevoCluster].clean = 1;

  pthread_mutex_unlock(&stFatMutex.bloqueaFat);
  pthread_mutex_unlock(&BitVecFat->bloqueastBits);
}

void quitarClusters(uint32_t ultimoClusArchivo,uint32_t nuevoUltimoCluster)
{
  extern stFatConMutex stFatMutex;
  extern stBits *BitVecFat;

    pthread_mutex_lock(&stFatMutex.bloqueaFat);
    stFatMutex.fatRegion[ultimoClusArchivo] = 0;
    stFatMutex.fatRegion[nuevoUltimoCluster] = FINARCHIVO;
    pthread_mutex_lock(&BitVecFat->bloqueastBits);
    BitVecFat[ultimoClusArchivo].ocupado = 0;
    BitVecFat[nuevoUltimoCluster].ocupado = 0;
    BitVecFat[ultimoClusArchivo].clean = 1;
    BitVecFat[nuevoUltimoCluster].clean = 1;
    pthread_mutex_unlock(&BitVecFat->bloqueastBits);
    pthread_mutex_unlock(&stFatMutex.bloqueaFat);
}
void achicarArchivo(uint32_t clusterInicial,uint32_t tamAnterior,uint32_t nuevoTam)
{
  extern stFatConMutex stFatMutex;
  extern stBits *BitVecFat;
  extern stBootSector sectorBoot;
  int32_t tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
  int32_t tamNuevo = nuevoTam;
  uint32_t deClusABloque,primerSecBloque;
  char *clusterVacio,*escribiOk;
  uint32_t clusterAnt = clusterInicial,nuevoCluster=0;
  clusterVacio = (char *)calloc(1,tamCluster);
  while (tamNuevo > 0)
    {
      clusterAnt = clusterInicial;
      clusterInicial = obtenerClusterSiguiente(clusterInicial);
      tamNuevo -= tamCluster;
    }
  pthread_mutex_lock(&stFatMutex.bloqueaFat);
  pthread_mutex_lock(&BitVecFat->bloqueastBits);

   while(clusterInicial != FINARCHIVO)
     {
       nuevoCluster = stFatMutex.fatRegion[clusterInicial];
       stFatMutex.fatRegion[clusterInicial] = 0x00;
       BitVecFat[clusterInicial].ocupado = 0;
       BitVecFat[clusterInicial].clean = 1;
       deClusABloque = deClusterABloque (clusterInicial);
       primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
       armarCluster (primerSecBloque,clusterVacio,&escribiOk);
       free(escribiOk);
       clusterInicial = nuevoCluster;
     }

  stFatMutex.fatRegion[clusterAnt] = FINARCHIVO;
  BitVecFat[clusterAnt].clean = 1;
  pthread_mutex_unlock(&stFatMutex.bloqueaFat);
  pthread_mutex_unlock(&BitVecFat->bloqueastBits);
  free(clusterVacio);

}
void agrandarArchivo(uint32_t clusterInicial,uint32_t tamAnterior,uint32_t nuevoTam)
{
  uint32_t cantClustersNuevos=0,cantClusAnt=0,cantClusTotal=0;
  uint32_t nuevoCluster=0,clusterAnterior=clusterInicial;
  extern stBootSector sectorBoot;
  extern stBits *BitVecFat;
  extern stFatConMutex stFatMutex;
  int32_t tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
  div_t cantNuevoTam,cantTamAnt;
  cantNuevoTam = div(nuevoTam,tamCluster);
  cantClusTotal = cantNuevoTam.quot;
  if (cantNuevoTam.rem > 0)
    cantClusTotal++;

  if (tamAnterior != 0)
    {
  cantTamAnt = div(tamAnterior,tamCluster);
  cantClusAnt = cantTamAnt.quot;
  if (cantTamAnt.rem > 0)
    cantClusAnt++;
    }
  else
    cantClusAnt = 1;

  cantClustersNuevos =  cantClusTotal - cantClusAnt;
  while (cantClusAnt > 1)
    {
      clusterAnterior = stFatMutex.fatRegion[clusterAnterior];
      cantClusAnt--;
    }
  pthread_mutex_lock(&stFatMutex.bloqueaFat);

  while (cantClustersNuevos > 0)
    {
      nuevoCluster = obtenerBitLibre();
      stFatMutex.fatRegion[clusterAnterior] = nuevoCluster;
      pthread_mutex_lock(&BitVecFat->bloqueastBits);
      BitVecFat[clusterAnterior].clean = 1;
      BitVecFat[nuevoCluster].clean = 1;
      pthread_mutex_unlock(&BitVecFat->bloqueastBits);
      clusterAnterior = nuevoCluster;
      cantClustersNuevos--;
    }

  stFatMutex.fatRegion[nuevoCluster] = FINARCHIVO;
  BitVecFat[nuevoCluster].clean = 1;
  BitVecFat[nuevoCluster].ocupado = 1;
  pthread_mutex_unlock(&stFatMutex.bloqueaFat);

}

char *buscarNombre (const char *path)
{
  char *aux = (char *)calloc(strlen(path) + 1,sizeof(char));

  char *spTokenSafe=NULL;
  char *retorno = ( char *) calloc (strlen(path),sizeof(char));
  memcpy(aux,path,strlen(path));
  aux = strtok_r (aux, "/", &spTokenSafe);

  while (aux != NULL)
    {
      memcpy (retorno, aux, strlen (aux));
      aux = strtok_r (NULL, "/", &spTokenSafe);

    }
  liberarMemoria(&aux);
  return retorno;
}
char *armarPath (const char* path)
{
  char *pathVariable;
  pathVariable = calloc (strlen (path) + 1, sizeof(char));
  memcpy (pathVariable, path, strlen (path));

  return pathVariable;
}

/*Devuelve el nro de Cluster Donde empieza la entrada buscada, y el offset Dentro de la entrada de directorio */
uint32_t buscarEntrada (uint32_t clusterInicial, char *entradaABuscar,uint32_t *offsetDirectorio, stDirectoryConNombreLargo *stEntradaLeida)
{
  extern stBootSector sectorBoot;
  extern t_config archivoCfg;
  uint32_t totalLeido = 0,nroClusterEncontrado = 0;
  uint8_t entradaEncontrada = 0,salir=0;
  char *sectoresDelClus;
  uint32_t primerSecBloque, deClusABloque;

  deClusABloque = deClusterABloque (clusterInicial);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque, NULL,&sectoresDelClus);
  /********************************************************/
  while (totalLeido < (archivoCfg.tamanioBloque * TAMSECTOR) && entradaEncontrada == 0 && salir == 0 )
    {
      *offsetDirectorio = totalLeido;
      leerEntradaDeDirectorio (stEntradaLeida,sectoresDelClus,&totalLeido);
      if (strcmp (stEntradaLeida->DTCN_FileName, entradaABuscar) == 0 && stEntradaLeida->EntradaDirectorio.DT_FileName[0] != ENTRADABORRADA)
        {
          entradaEncontrada = 1;
          nroClusterEncontrado = armarClusterInicial (stEntradaLeida->EntradaDirectorio.DT_ClusterInicialHigh,stEntradaLeida->EntradaDirectorio.DT_ClusterInicialLow);

        }

      if (stEntradaLeida->EntradaDirectorio.DT_FileName[0] == NOHAYMASENTRADAS)
        salir = 1;
    }

  free (sectoresDelClus);

  if (salir == 1)
    return FINARCHIVO; /*MANDO FINARCHIVO Para Decir que no existe la entrada */

  return nroClusterEncontrado;
}

void borrarEntradaDirectorio(uint32_t clusterDirectorio,uint32_t offset,stDirectoryConNombreLargo *stDirABorrar)
{
  char *retEscritura,*cluster;
  uint32_t deClusABloque, primerSecBloque,tamEntrada=0;
  stLongFileName entradaABorrar;
  tamEntrada =sizeof(stLongFileName);
  deClusABloque = deClusterABloque (clusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque,NULL ,&cluster);

  memset(&entradaABorrar,'\0',tamEntrada);
  cargarNombreLargo(&entradaABorrar,stDirABorrar->DTCN_FileName);
  entradaABorrar.LFN_secuenceNumber = ENTRADABORRADA;
  entradaABorrar.LFN_Atributos = NOMBRELARGO;
  stDirABorrar->EntradaDirectorio.DT_FileName[0] = ENTRADABORRADA;
  memcpy(cluster + offset,&entradaABorrar,tamEntrada);

  offset += tamEntrada;
  memcpy(cluster + offset,&stDirABorrar->EntradaDirectorio,sizeof(stDirectoryTable));
  armarCluster (primerSecBloque, cluster,&retEscritura);

  free(retEscritura);
  free(cluster);
}
void modificarEntradaDirectorio (stDirectoryConNombreLargo stEntrada,uint32_t offsetDirectorio, uint32_t nroClusterDirectorio)
{
  uint32_t deClusABloque, primerSecBloque, tamEntrada;
  char *clusterModificado,*retEscritura;
  stLongFileName stNombreLargoAEscribir;
  deClusABloque = deClusterABloque (nroClusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque, NULL,&clusterModificado);

  tamEntrada = sizeof (stEntrada.EntradaDirectorio);
  crearEntradasDirectorio(&stEntrada.EntradaDirectorio,&stNombreLargoAEscribir,stEntrada.DTCN_FileName);
  memcpy (clusterModificado + offsetDirectorio,&stNombreLargoAEscribir, tamEntrada);
  memcpy (clusterModificado + offsetDirectorio + tamEntrada,&stEntrada.EntradaDirectorio, tamEntrada);

  armarCluster (primerSecBloque,clusterModificado,&retEscritura);
  free(retEscritura);
  free(clusterModificado); // Lo quiero liberar Aca???
}

void leerEntradaDeDirectorio (stDirectoryConNombreLargo *stEntradaDirARetornar,char *sector,uint32_t *cantLeido)
{

  uint8_t tamEntradaDir = 32,lengthNombre=0,largoNombre=0;
  stLongFileName stArchivosNombreLargo;
  int8_t tamNombreLargo = 14,posAtrib=11;
  uint8_t atrib=0;
  char *nombreLargo;
  nombreLargo = ( char *) calloc (tamNombreLargo, sizeof(char));

  memcpy(&atrib,sector + *cantLeido + posAtrib,sizeof(uint8_t)); // 11 es la posicion del atrib
  memset(stEntradaDirARetornar->DTCN_FileName,'\0',tamNombreLargo);
  if (atrib == 0x0F)
    {
      memcpy (&stArchivosNombreLargo, sector + *cantLeido, tamEntradaDir);
      *cantLeido += tamEntradaDir;
      memcpy (&stEntradaDirARetornar->EntradaDirectorio, sector + *cantLeido,tamEntradaDir);
      lengthNombre = armarNombreLargo (stArchivosNombreLargo,&nombreLargo);
      memcpy (stEntradaDirARetornar->DTCN_FileName,nombreLargo,lengthNombre);
      *cantLeido += tamEntradaDir;
    }
  else
    {
      memcpy (&stEntradaDirARetornar->EntradaDirectorio, sector + *cantLeido, tamEntradaDir);
      for(largoNombre=0;*(stEntradaDirARetornar->EntradaDirectorio.DT_FileName + largoNombre) != ' ' && largoNombre < 8;largoNombre++);
      memcpy (stEntradaDirARetornar->DTCN_FileName,stEntradaDirARetornar->EntradaDirectorio.DT_FileName,largoNombre);
      memcpy (stEntradaDirARetornar->DTCN_FileName + largoNombre ,".",1);
      largoNombre++;
      memcpy (stEntradaDirARetornar->DTCN_FileName + largoNombre,stEntradaDirARetornar->EntradaDirectorio.DT_Extension,sizeof(stEntradaDirARetornar->EntradaDirectorio.DT_Extension));
      *cantLeido += tamEntradaDir;
    }
  free (nombreLargo);
}

uint32_t leerSubDirectorios (char *entradaABuscar, uint32_t *offsetDirectorio,stDirectoryConNombreLargo *stEntradaLeida, uint32_t *clusterDirectorio)
{
  extern stBootSector sectorBoot;
  char *spTokenSafe;
  char token [] = "/";
  char *palabra;
  uint32_t clusterEntrada = sectorBoot.BPB_RootClus;
  int8_t comparaEntrada = (strcmp (entradaABuscar, token));
  if (comparaEntrada == 0) /* ----> Quiero Listar El Directorio Raiz, Ya tengo el Nro de Cluster entonces lo devuelvo */
    return clusterEntrada;

  palabra = strtok_r (entradaABuscar, token, &spTokenSafe);
  while (palabra != NULL)
    {
      *clusterDirectorio = clusterEntrada;

      clusterEntrada = buscarEntrada (*clusterDirectorio, palabra,offsetDirectorio, stEntradaLeida);
      palabra = strtok_r (NULL, token, &spTokenSafe);
    }
  return clusterEntrada;
}

void buscarEntradaLibre (uint32_t clusterDirectorio,uint32_t *offset, char **cluster) // Devuelvo el offset donde puedo cargar Mi Nueva Entrada (Libre o Borrada)
{
  extern stBootSector sectorBoot;
  uint32_t deClusABloque, primerSecBloque;
  uint32_t recorroCluster = 0;
  uint8_t atrib=1;
  stDirectoryConNombreLargo stEntradaDirARetornar;
  deClusABloque = deClusterABloque (clusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque, NULL,cluster);
  while (recorroCluster < sectorBoot.BPB_SecPerClus * TAMSECTOR && atrib != NOHAYMASENTRADAS && atrib != ENTRADABORRADA)
    {
      *offset = recorroCluster;
      leerEntradaDeDirectorio(&stEntradaDirARetornar,*cluster,&recorroCluster);
      memcpy(&atrib,stEntradaDirARetornar.EntradaDirectorio.DT_FileName,sizeof(char));
    }

}
void renombrarArchivo (const char *from,char *nuevoNombre)
{
  uint32_t leerDirectorio,offset,clusterDirectorio=0;
  stDirectoryConNombreLargo entradaLeida;
  char *pathVariable;
  pathVariable = armarPath (from);
  leerDirectorio = leerSubDirectorios(pathVariable,&offset,&entradaLeida,&clusterDirectorio);
  memcpy(entradaLeida.DTCN_FileName,nuevoNombre,sizeof(entradaLeida.DTCN_FileName));
  modificarEntradaDirectorio(entradaLeida,offset,clusterDirectorio);
  free(pathVariable);
}
void cargarNuevaEntrada(uint32_t clusterDirectorio,uint32_t offsetAEscribir,stDirectoryConNombreLargo entradaLeida)
{
  stLongFileName entradaLFN;
  char *retEscritura,*cluster;
  uint32_t deClusABloque,primerSecBloque;
  uint32_t tamEntrada =sizeof(stLongFileName);

  memset(&entradaLFN,'\0',tamEntrada);
  cargarNombreLargo(&entradaLFN,entradaLeida.DTCN_FileName);
  entradaLFN.LFN_Atributos = NOMBRELARGO;
  entradaLFN.LFN_secuenceNumber = 0x41;

  /* Obtengo El Cluster Del Directorio A Modificar */
  deClusABloque = deClusterABloque (clusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque,NULL,&cluster);

  memcpy(cluster + offsetAEscribir,&entradaLFN,tamEntrada);
  offsetAEscribir += tamEntrada;
  memcpy(cluster + offsetAEscribir,&entradaLeida.EntradaDirectorio,sizeof(entradaLeida.EntradaDirectorio));

  /* Lo SobreEscribo Una Vez Modificado */
  deClusABloque = deClusterABloque (clusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque,cluster,&retEscritura);

  free(retEscritura);
  free(cluster);

}
uint32_t moverArchivo(const char *from,const char *to,char *nuevoNombre)
{
  uint32_t leerDirectorio,offset,clusterDirectorio=0;
  uint32_t nuevoOffset,nuevoClusterDir=0;
  stDirectoryConNombreLargo entradaLeida;
  char *pathViejo,*pathNuevo;


  pathViejo = armarPath (from);
  pathNuevo = armarPath (to);

  leerDirectorio = leerSubDirectorios(pathNuevo,&nuevoOffset,&entradaLeida,&nuevoClusterDir);

  if (leerDirectorio != FINARCHIVO) // Ya Existe Un Archivo Con ese nombre
    {
      return -errno;
    }

  leerDirectorio = leerSubDirectorios(pathViejo,&offset,&entradaLeida,&clusterDirectorio);



  cargarNuevaEntrada(nuevoClusterDir,nuevoOffset,entradaLeida);
  borrarEntradaDirectorio(clusterDirectorio,offset,&entradaLeida);




  free(pathViejo);
  free(pathNuevo);


  return 0;
}
uint32_t obtenerUltimoCLusterLeido (uint32_t clusterInicial, uint32_t offset)
{
  extern stBootSector sectorBoot;
  int32_t cantClustersLeidos;
  int32_t recorroFAT = 0;
  uint32_t cluster = clusterInicial;
  cantClustersLeidos = offset / (sectorBoot.BPB_SecPerClus * TAMSECTOR);
  while (recorroFAT < cantClustersLeidos)
    {
      cluster = obtenerClusterSiguiente (cluster);
      recorroFAT++;
    }
  return cluster;
}
uint32_t obtenerUltimoCLusterEscrito (uint32_t clusterInicial, uint32_t offset)
{
  extern stBootSector sectorBoot;
  uint32_t cluster = clusterInicial;
  uint32_t tamCluster = sectorBoot.BPB_SecPerClus * TAMSECTOR;

  while (cluster != FINARCHIVO && offset >= tamCluster)
    {
      cluster = obtenerClusterSiguiente (cluster);
      offset -= tamCluster;
    }
  return cluster;
}
uint32_t obtenerNuevoCluster(uint32_t clusterInicial,uint32_t offset)
{
 uint32_t nuevoCluster,cantARecorrer=0;
 uint32_t ultimoCluster=clusterInicial,tamCluster;
 extern stBootSector sectorBoot;
 extern stBits *BitVecFat;
 extern stFatConMutex stFatMutex;
 nuevoCluster = obtenerclusterNuevo();
 tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
 cantARecorrer = offset /tamCluster;
 while (cantARecorrer > 0 && clusterInicial != FINARCHIVO)
   {
     ultimoCluster = clusterInicial;
     clusterInicial = obtenerClusterSiguiente (clusterInicial);
     cantARecorrer--;
   }
 pthread_mutex_lock(&stFatMutex.bloqueaFat);
 pthread_mutex_lock(&BitVecFat->bloqueastBits);
 stFatMutex.fatRegion[ultimoCluster] = nuevoCluster;
 stFatMutex.fatRegion[nuevoCluster] = FINARCHIVO;
 BitVecFat[ultimoCluster].clean = 1;
 BitVecFat[nuevoCluster].clean = 1;
 pthread_mutex_unlock(&stFatMutex.bloqueaFat);
 pthread_mutex_unlock(&BitVecFat->bloqueastBits);
 return nuevoCluster;
}
void leerArchivos (uint32_t clusterInicial, char **cluster)
{

  uint32_t deClusABloque, primerSecBloque;

  deClusABloque = deClusterABloque (clusterInicial);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque, NULL,cluster);

}
uint32_t escribeArchivos (uint32_t clusterInicial, char *Payload)
{
  uint32_t deClusABloque, primerSecBloque;
  char *cluster;
  extern stBootSector sectorBoot;

  deClusABloque = deClusterABloque (clusterInicial);
  primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
  armarCluster (primerSecBloque,Payload,&cluster);
  liberarMemoria(&cluster);


  return 0;
}

uint32_t modificarArchivos(uint32_t clusterInicial, char *Payload,uint32_t offset,size_t size)
{
   uint32_t deClusABloque, primerSecBloque;
   char *cluster,*retEscritura;

   deClusABloque = deClusterABloque (clusterInicial);
   primerSecBloque = obtenerPrimerSectorDeUnBloque (deClusABloque);
   armarCluster (primerSecBloque,NULL,&cluster);
   memcpy(cluster + offset,Payload,size);
   armarCluster (primerSecBloque,cluster,&retEscritura);

   free(cluster);
   free(retEscritura);

  return 0;
}
